
#ifndef REQUESTHANDLER_H_
#define REQUESTHANDLER_H_


#include "ConnectionProxy.h"
#include "../Engine/ResultListener.h"
#include "../Packets/PubPkt.h"
#include "../Packets/Pkt.h"
#include "../Packets/UnSubPkt.h"
#include "../Packets/PingPkt.h"
#include "CharVector.h"
#include "../Marshalling/BufferedPacketUnmarshaller.h"
#include "../Marshalling/PacketMarshaller.h"
#include <set>
#include <vector>
#include "ConnectionTable.h"
#include "../Interface/StorexEngine.h"


class RequestHandler{
public:
	RequestHandler(ConnectionProxy& connection, int connectionId, ConnectionTable* connectionTable, StorexEngine& storexEngine);
	~RequestHandler();

	template <std::size_t N>  // defined here because of the template
	void handleRequest(CharArray<N> & recBytes, std::size_t recBytesNum){
		std::vector<PktPtr> pkts= unmarshaller.unmarshal<N>(recBytes, recBytesNum);
		handleRequest(pkts);
	}

private:
	class PktHandleVisitor : public boost::static_visitor<>{
		RequestHandler &parent;
	public:
		PktHandleVisitor(RequestHandler& p): parent(p) { }
		void operator()(RulePkt * pkt) const;
		void operator()(PubPkt * pkt) const;
		void operator()(BackSubPkt * pkt) const;
		void operator()(SubPkt * pkt) const;
		void operator()(UnSubPkt * pkt) const;
		void operator()(PingPkt * pkt) const;
	};

	class ResultListenerImpl: public ResultListener{
		RequestHandler &parent;
	public:
		ResultListenerImpl(RequestHandler& p): parent(p) { }
		virtual ~ResultListenerImpl() { }
		void handleResult(set<PubPkt *> &genPkts, double procTime);
	};

	ConnectionProxy& connection;
	ResultListenerImpl resultListener;

	BufferedPacketUnmarshaller unmarshaller;
	PacketMarshaller marshaller;

	vector<BackSubPkt> subscriptions;
	bool firstSubscriptionDone;

	CharVector lastRequest;

	int connectionId;
	ConnectionTable *connectionTable;
	StorexEngine& storexEngine;

	void handleRequest(std::vector<PktPtr> & pkts);
	void handleRulePkt(RulePkt* pkt);
	void handlePubPkt(PubPkt* pkt);
	void handleSubPkt(SubPkt* pkt);
	void handleSubPkt(BackSubPkt* pkt);
	void handleAdvPkt(AdvPkt* pkt);
};


#endif /* REQUESTHANDLER_H_ */
